﻿using System.Net;
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Dysmsapi20170525;
using AlibabaCloud.SDK.Dysmsapi20170525.Models;
using Devonline.AspNetCore;
using Devonline.Core;
using Microsoft.Extensions.Logging;

namespace Devonline.CloudService.Aliyun;

/// <summary>
/// 阿里云接口短信发送服务
/// </summary>
public class SmsService : ISmsService<SmsModel>
{
    private readonly ILogger<SmsService> _logger;
    private readonly Client _client;
    private readonly SmsModel _smsModel;
    public SmsService(ILogger<SmsService> logger, ISmsEndpoint endpoint, SmsModel smsModel)
    {
        ArgumentNullException.ThrowIfNull(endpoint.Host);
        ArgumentNullException.ThrowIfNull(endpoint.Id);
        ArgumentNullException.ThrowIfNull(endpoint.Secret);
        ArgumentNullException.ThrowIfNull(smsModel.SignName);
        ArgumentNullException.ThrowIfNull(smsModel.TemplateCode);
        _logger = logger;
        _smsModel = smsModel;
        _client = new Client(new Config { Endpoint = endpoint.Host, AccessKeyId = endpoint.Id, AccessKeySecret = endpoint.Secret });
    }

    /// <summary>
    /// 阿里云接口发送短信
    /// </summary>
    /// <param name="model">短信内容数据模型</param>
    /// <returns></returns>
    public async Task SendAsync(SmsModel model)
    {
        var request = GetSmsRequest(model.TemplateParam, model.PhoneNumbers.ToArray());
        _logger.LogInformation("The sms service will send sms message to: " + request.PhoneNumbers);
        var response = await _client.SendSmsAsync(request);
        switch (response.StatusCode)
        {
            case (int)HttpStatusCode.OK when response.Body.Code == HttpStatusCode.OK.ToString():
                _logger.LogInformation($"The sms service send sms message success with code: {response.Body.Code}, message: {response.Body.Message}, and sms content: {model.ToJsonString()}");
                break;
            default:
                throw new Exception($"The sms service send sms message failed with code: {response.Body.Code}, message: {response.Body.Message}");
        }
    }
    /// <summary>
    /// 发送短信息
    /// </summary>
    /// <param name="templateParam">短信内容模板中的变量和值的集合</param>
    /// <param name="phoneNumbers">默认发送的手机号码, phoneNumbers 或者 TSmsModel.PhoneNumbers 必须有一个有值</param>
    /// <returns></returns>
    public async Task SendAsync(Dictionary<string, string> templateParam, params string[] phoneNumbers)
    {
        var request = GetSmsRequest(templateParam, phoneNumbers);
        _logger.LogInformation("The sms service will send sms message to: " + request.PhoneNumbers);
        var response = await _client.SendSmsAsync(request);
        switch (response.StatusCode)
        {
            case (int)HttpStatusCode.OK when response.Body.Code == HttpStatusCode.OK.ToString():
                _logger.LogInformation($"The sms service send sms message success with code: {response.Body.Code}, message: {response.Body.Message}, and sms content: {request.ToJsonString()}");
                break;
            default:
                throw new Exception($"The sms service send sms message failed with code: {response.Body.Code}, message: {response.Body.Message}");
        }
    }

    /// <summary>
    /// 发送手机验证码
    /// </summary>
    /// <param name="phoneNumbers">默认发送的手机号码, phoneNumbers 或者 TSmsModel.PhoneNumbers 必须有一个有值</param>
    /// <returns></returns>
    public async Task<string> SendCaptchaAsync(params string[] phoneNumbers)
    {
        var phoneNumberStrings = phoneNumbers.ToString<string>();
        var code = new Random(DateTime.Now.Millisecond).Next(100000, 999999).ToString();
        _logger.LogDebug($"SMS service will send captcha: {code} to {phoneNumberStrings}");
        await SendAsync(new Dictionary<string, string> { { nameof(code), code } }, phoneNumbers);
        _logger.LogInformation($"SMS service send captcha: {code} to {phoneNumberStrings} success");
        return code;
    }

    /// <summary>
    /// 发送短信息
    /// </summary>
    /// <param name="templateParam">短信内容模板中的变量和值的集合</param>
    /// <param name="phoneNumbers">默认发送的手机号码, phoneNumbers 或者 TSmsModel.PhoneNumbers 必须有一个有值</param>
    /// <returns></returns>
    private SendSmsRequest GetSmsRequest(Dictionary<string, string> templateParam, params string[] phoneNumbers)
    {
        if (phoneNumbers.Length == 0)
        {
            phoneNumbers = _smsModel.PhoneNumbers.ToArray();
        }

        if (phoneNumbers.Length == 0)
        {
            throw new Exception("the sms service send message need phone number(s)!");
        }

        templateParam = templateParam.Where(x => _smsModel.TemplateParam.Select(a => a.Key).Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value);
        return new SendSmsRequest
        {
            SignName = _smsModel.SignName,
            TemplateCode = _smsModel.TemplateCode,
            PhoneNumbers = phoneNumbers.ToString<string>(),
            TemplateParam = templateParam.ToJsonString(),
        };
    }
}